
#include "OpenGL.h"
#include "Camera.h"
#include "Mouse.h"
#include "Light.h"
#include "MaterialManager.h"
#include "Rock.h"
#include "RockManager.h"
#include "Utility.h"

using namespace Velyn;

//-------------------------------------------------------------------------------
// Prototypes
//-------------------------------------------------------------------------------

void display();
void keyboardPress(unsigned char key, int x, int y);
void keyboardRelease(unsigned char key, int x, int y);
void reshape(int w, int h);
void timer(int extra);
void initialize();
void mouseButtonPress(int button, int state, int x, int y);
void mouseMotion(int x, int y);

//-------------------------------------------------------------------------------
// Globals
//-------------------------------------------------------------------------------

Camera camera;
IO::Mouse mouse;
Light light;
// RockManager rockManager;
Rock rock("/Users/n7down/Source/Velyn/textures/8.tga", "default");

//-------------------------------------------------------------------------------
// Display
//-------------------------------------------------------------------------------

void display() {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
    // enable the camera
    camera.enable();
    
    // rotate the scene according to the input of the mouse
    mouse.rotateObject();
    
    // show compass
    Graphics::Utility::Compass::render();
    
    // render
    // rockManager.render();
    rock.render();
    
    glutSwapBuffers();
}

//-------------------------------------------------------------------------------
// Keyboard Press
//-------------------------------------------------------------------------------

void keyboardPress(unsigned char key, int x, int y) {
	switch(key) {
		case 27: {
			exit(0);
		} break;
			
		case '`': {
			// console stuff..
		} break;
			
		case 'a': {
            // rockManager.sample();
            rock.sperical(1);
        } break;
            
        case 's': {
            rock.slice(1);
        } break;
            
        case 'd': {
            // rock.smooth(1);
            rock.noise(1);
            
        } break;
            
        case 'z': {
            rock.reset();
        } break;
            
		case 'w': {	
			MeshRenderer::getInstance()->wireframeToggle();
		} break;
            
        case 'v': {
            MeshRenderer::getInstance()->verticesToggle();
        } break;
            
        case 'n': {
            MeshRenderer::getInstance()->normalToggle();
        } break;

		default: {
			
		} break;
	}
}

//-------------------------------------------------------------------------------
// Keyboard Release
//-------------------------------------------------------------------------------

void keyboardRelease(unsigned char key, int x, int y) {}

//-------------------------------------------------------------------------------
// Reshape
//-------------------------------------------------------------------------------

void reshape(int w, int h) {
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, 1.6, 1.0, 200.0);
}

//-------------------------------------------------------------------------------
// Timer
//-------------------------------------------------------------------------------

// this is for animations
void timer(int extra) {
    // camera.animate();
    // rockManager.animate();
	glutPostRedisplay();
	glutTimerFunc(40, timer, 0);
} 

//-------------------------------------------------------------------------------
// Initialize
//-------------------------------------------------------------------------------

void initialize() {
    
	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
	glShadeModel(GL_SMOOTH);
    
    // set camera
    camera.setDistance(4.0f);

    // load materials
    MaterialManager::getInstance()->loadMaterials("/Users/n7down/Source/Velyn/core/materials.txt");
    
    // enable lighting
    light.enable();
    
    // use textures
    rock.bindTexture();
    
    // use materials
    rock.useMaterial();
    
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_NORMALIZE);
    
	glMatrixMode(GL_PROJECTION);		
	glLoadIdentity();
	gluPerspective(45.0, 1.6, 1.0, 200.0);
}

//-------------------------------------------------------------------------------
// Mouse Press
//-------------------------------------------------------------------------------

void mouseButtonPress(int button, int state, int x, int y) {
    mouse.pressEvent(button, state, x, y);
}

//-------------------------------------------------------------------------------
// Mouse Motion
//-------------------------------------------------------------------------------

void mouseMotion(int x, int y) {
    mouse.motionEvent(x, y);
}

//-------------------------------------------------------------------------------
// Main
//-------------------------------------------------------------------------------

int main(int argc, char** argv) {
	
    glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(800, 500);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("Procedural Modeling of Rocks");
	initialize();
	
	glutKeyboardFunc(keyboardPress);
	glutKeyboardUpFunc(keyboardRelease);
	
	glutMouseFunc(mouseButtonPress);
	glutMotionFunc(mouseMotion);
	
	glutTimerFunc(25, timer, 0);
	glutDisplayFunc(display);
	
	glutReshapeFunc(reshape);
    
	glutMainLoop();
}
